require 'common.class'
local skynet = require "skynet"
local protobuf = require "protobuf"
kcpAgent = class('kcpAgent')

function kcpAgent:ctor()
    self.loginAgent = nil
    self.playerId = nil
    self.conv = nil
    self.receivedPing = false
end

function kcpAgent:Start()
    local CMD = {}
    function CMD.Start(loginAgent, playerId)
        self.playerId = playerId
        self.loginAgent = loginAgent
        local success, conv = skynet.call('kcpGate', 'lua', 'CMD', 'CreateSession', {
            avatar = skynet.self()
        })
        self.conv = conv
        return conv
    end

    function CMD.OnLoginAgentDisconnect(loginAgent)
        self.loginAgent = loginAgent
    end

    function CMD.OnReconnect(loginAgent, playerId, conv)
        if playerId ~= self.playerId then return false end
        if conv ~= self.conv then return false end
        if self.loginAgent then
            skynet.call(self.loginAgent, 'lua', 'kick')
        end
        self.loginAgent = loginAgent
        return self.conv
    end

    local function send_package(msgID, requestID, pack)
        local message = {
            messageType = msgID,
            requestID = requestID,
            code = 'SUCCESS',
            data = pack,
        }
        local bytes = protobuf.encode("Protocol", message)
        local package = string.pack(">s2", bytes)
        skynet.send('kcpGate', 'lua', 'SOCKET', 'SendMessage', skynet.self(), package)
    end

    local function send_exception(msgID, requestID, code)
        local message = {
            messageType = msgID,
            requestID = requestID,
            code = code,
        }
        local bytes = protobuf.encode("Protocol", message)
        local package = string.pack(">s2", bytes)
        skynet.send('kcpGate', 'lua', 'SOCKET', 'SendMessage', skynet.self(), package)
    end

    function CMD.OnRecvKcpMsg(messages)
        self.pingReceived = true
        for _, message in ipairs(messages) do
            local msgID, requestID, content = message[1], message[2], message[3]
            local result = nil
            xpcall(function()
                if self[msgID] then
                    result = self[msgID](self, content)
                end
            end, function(error)
                send_exception(msgID, requestID, error)
            end)

            if result then
                send_package(msgID, requestID, result)
            end
        end
    end

    --检测udp长时间没收到任何消息断开
    self.pingReceived = false
    local function disconnect()
        pcall(function() self:OnDisconnect() end)
        skynet.call('kcpGate', 'lua', 'CMD', 'CloseSession')
        skynet.call('avatarManager', 'lua', 'CMD', 'RemoveAvatar', self.playerId)
        skynet.exit()
    end
    skynet.fork(function()
        while true do
            skynet.sleep(100 * 60 * 5)
            if self.pingReceived then
                self.pingReceived = false
            else
                disconnect()
            end
        end
    end)

    skynet.start(function()
        skynet.dispatch("lua", function(_,_, command, ...)
            local f = CMD[command]
            skynet.ret(skynet.pack(f(...)))
        end)
    end)
end

function kcpAgent:OnDisconnect() end